#pragma once
#include <Dynamics/Fem/fem_cpu.h>

namespace PhysLeo {

/**
 * FEM gpu model, extends the ForceModule interface.
 * implement the classical finite element method for simulation. For non-constant strain element, use the gauss quadrature method.
 * you can choose different numbers of gauss quadrature points. 
 */
template<typename T>
class FemCuda : public FemCpu<T> {
public:
    /**
    * empty constructor, set everything to its default value
    */
    FemCuda();

    /**
    * allocate resource.
    * @param[in] simData  a data structure manage the simulation data.
    */
    void allocateResource(SimData<T>& simData) override;

protected:
    /**
    * precompute the shape matrix for cubic element, store it in ptr_shape_matrix_
    */
    void cubicShapeMatrix() override;

    /**
    * precompute the shape matrix for tet element, store it in ptr_shape_matrix_
    */
    void tetShapeMatrix() override;

    /**
    * return the internal force by FEM cubic elements.
    * @param[in] ptr_pos  current position of the system
    * @param[in] ptr_force  internal force of the system according to current position.
    */
    void cubicInternalForce(std::shared_ptr<BufferData<glm::tvec3<T>>> ptr_pos, std::shared_ptr<BufferData<glm::tvec3<T>>> ptr_force)override;

    /**
    * return the internal force by FEM tet elements.
    * @param[in] ptr_pos  current position of the system
    * @param[in] ptr_force  internal force of the system according to current position.
    */
    void tetInternalForce(std::shared_ptr<BufferData<glm::tvec3<T>>> ptr_pos, std::shared_ptr<BufferData<glm::tvec3<T>>> ptr_force)override;
};

}